<?php
/*
 * program:	均源
 * author:	雨中漫步 & 上善若水 & qhxin
 * email:	qhxin@qhxin.com
 * date:	2014/11/11
 * description:	又是一年双十一，不能剁手，就写点东西吧~~~~~~
 */

defined('IN_SCHOOL') or die();

/*{TranslateTagBegin}*/
class http {

    /*
	下载远程文件，保存到本地，需CURL支持
    */
    public static function curlDownload($url,$local) {
        $cp = curl_init($url);
        $fp = fopen($local,"w");
        curl_setopt($cp, CURLOPT_FILE, $fp);
        curl_setopt($cp, CURLOPT_HEADER, 0);
        curl_exec($cp);
        curl_close($cp);
        fclose($fp);
    }

	/*
	使用 fsockopen 通过 HTTP 协议直接访问(采集)远程文件
	如果主机或服务器没有开启 CURL 扩展可考虑使用
	fsockopen 比 CURL 稍慢,但性能稳定
	$url 远程URL
	$conf //其他配置信息
		$conf = array(
		'limit', //分段读取字符个数
		'post',  //post的内容,字符串或数组,key=value&形式
		'cookie', //携带cookie访问,该参数是cookie内容
		'ip',    //如果该参数传入,$url将不被使用,ip访问优先
		'timeout', //访问超时时间
		'block' //是否阻塞访问,默认为true
		)
    */
    static public function fsockopenDownload($url, $conf = array()) {
        $return = '';
        if(!is_array($conf)) return $return;

        $matches = parse_url($url);
        !isset($matches['host']) 	&& $matches['host'] 	= '';
        !isset($matches['path']) 	&& $matches['path'] 	= '';
        !isset($matches['query']) 	&& $matches['query'] 	= '';
        !isset($matches['port']) 	&& $matches['port'] 	= '';
        $host = $matches['host'];
        $path = $matches['path'] ? $matches['path'].($matches['query'] ? '?'.$matches['query'] : '') : '/';
        $port = !empty($matches['port']) ? $matches['port'] : 80;

        $conf_arr = array(
            'limit'		=>	0,
            'post'		=>	'',
            'cookie'	=>	'',
            'ip'		=>	'',
            'timeout'	=>	15,
            'block'		=>	TRUE,
            );

        foreach (array_merge($conf_arr, $conf) as $k=>$v) ${$k} = $v;

        if($post) {
            if(is_array($post))
            {
                $post = http_build_query($post);
            }
            $out  = "POST $path HTTP/1.0\r\n";
            $out .= "Accept: */*\r\n";
            $out .= "Accept-Language: zh-cn\r\n";
            $out .= "Content-Type: application/x-www-form-urlencoded\r\n";
            $out .= "User-Agent: $_SERVER[HTTP_USER_AGENT]\r\n";
            $out .= "Host: $host\r\n";
            $out .= 'Content-Length: '.strlen($post)."\r\n";
            $out .= "Connection: Close\r\n";
            $out .= "Cache-Control: no-cache\r\n";
            $out .= "Cookie: $cookie\r\n\r\n";
            $out .= $post;
        } else {
            $out  = "GET $path HTTP/1.0\r\n";
            $out .= "Accept: */*\r\n";
            $out .= "Accept-Language: zh-cn\r\n";
            $out .= "User-Agent: $_SERVER[HTTP_USER_AGENT]\r\n";
            $out .= "Host: $host\r\n";
            $out .= "Connection: Close\r\n";
            $out .= "Cookie: $cookie\r\n\r\n";
        }
        $fp = @fsockopen(($ip ? $ip : $host), $port, $errno, $errstr, $timeout);
        if(!$fp) {
            return '';
        } else {
            stream_set_blocking($fp, $block);
            stream_set_timeout($fp, $timeout);
            @fwrite($fp, $out);
            $status = stream_get_meta_data($fp);
            if(!$status['timed_out']) {
                while (!feof($fp)) {
                    if(($header = @fgets($fp)) && ($header == "\r\n" ||  $header == "\n")) {
                        break;
                    }
                }

                $stop = false;
                while(!feof($fp) && !$stop) {
                    $data = fread($fp, ($limit == 0 || $limit > 8192 ? 8192 : $limit));
                    $return .= $data;
                    if($limit) {
                        $limit -= strlen($data);
                        $stop = $limit <= 0;
                    }
                }
            }
            @fclose($fp);
            return $return;
        }
    }

	/*
	HTTPS访问，需CURL支持
	*/
	public static function https_fetch_url($url, $timeout=30, $header=array()) {
		if(substr($url, 0, 5) == 'http:') {
			return self::fetch_url($url, $timeout);
		}
		$w = stream_get_wrappers();
		$allow_url_fopen = strtolower(ini_get('allow_url_fopen'));
		$allow_url_fopen = (empty($allow_url_fopen) || $allow_url_fopen == 'off') ? 0 : 1;
		if(extension_loaded('openssl') && in_array('https', $w) && $allow_url_fopen) {
			return file_get_contents($url);
		} elseif (!function_exists('curl_init')) {
			throw new Exception('server not installed curl.');
		}
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_HEADER, 1);
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_USERAGENT, core::gpc('HTTP_USER_AGENT', 'S'));
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1); // 从证书中检查SSL加密算法是否存在
		curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
		if(!empty($header)) {
			curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
		}
		$data = curl_exec($ch);
		if(curl_errno($ch)) {
			throw new Exception('Errno'.curl_error($ch));//捕抓异常
		}
		if(!$data) {
			curl_close($ch);
			return '';
		}
		
		list($header, $data) = explode("\r\n\r\n", $data);
		$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
		if($http_code == 301 || $http_code == 302) {
			$matches = array();
			preg_match('/Location:(.*?)\n/', $header, $matches);
			$url = trim(array_pop($matches));
			curl_setopt($ch, CURLOPT_URL, $url);
			curl_setopt($ch, CURLOPT_HEADER, false);
			$data = curl_exec($ch);
		}
		curl_close($ch);
		return $data;  
	}

	/*
	HTTP访问，需CURL支持，可发送Referer
	*/
	public static function fetch_url($url, $timeout = 5, $post = '', $cookie = '', $deep = 0,$cookiefile = '',$sendcookie = false,$refer = '') {
		if($deep > 5) throw new Exception('超出 fetch_url() 最大递归深度！');
		if(substr($url, 0, 5) == 'https') {
			return self::https_fetch_url($url, $timeout);
		}
		
		$w = stream_get_wrappers();
		$allow_url_fopen = strtolower(ini_get('allow_url_fopen'));
		$allow_url_fopen = (empty($allow_url_fopen) || $allow_url_fopen == 'off') ? 0 : 1;
		if(function_exists('fsockopen') && empty($cookiefile)) {
			$limit = 500000;
			$ip = '';
			$return = '';
			$matches = parse_url($url);
			$host = $matches['host'];
			$path = $matches['path'] ? $matches['path'].(!empty($matches['query']) ? '?'.$matches['query'] : '') : '/';
			$port = !empty($matches['port']) ? $matches['port'] : 80;
		
			$HTTP_USER_AGENT = core::gpc('$HTTP_USER_AGENT', 'S');
			empty($HTTP_USER_AGENT) && $HTTP_USER_AGENT = 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)';
			if(empty($post)) {
				$out = "GET $path HTTP/1.0\r\n";
				$out .= "Accept: */*\r\n";
				$out .= "Accept-Language: zh-cn\r\n";
				if(!empty($refer))$out .= "Referer: $refer\r\n";
				$out .= "User-Agent: $HTTP_USER_AGENT\r\n";
				$out .= "Host: $host\r\n";
				$out .= "Connection: Close\r\n";
				$out .= "Cookie:$cookie\r\n\r\n";
			} else {
				$out = "POST $path HTTP/1.0\r\n";
				$out .= "Accept: */*\r\n";
				$out .= "Accept-Language: zh-cn\r\n";
				if(!empty($refer))$out .= "Referer: $refer\r\n";
				$out .= "User-Agent: $HTTP_USER_AGENT\r\n";
				$out .= "Host: $host\r\n";
				$out .= 'Content-Length: '.strlen($post)."\r\n";
				$out .= "Content-Type: application/x-www-form-urlencoded\r\n";
				$out .= "Connection: Close\r\n";
				$out .= "Cache-Control: no-cache\r\n";
				$out .= "Cookie:$cookie\r\n\r\n";
				$out .= $post;
			}
			$host == 'localhost' && $ip = '127.0.0.1';
			$fp = @fsockopen(($ip ? $ip : $host), $port, $errno, $errstr, $timeout);
			if(!$fp) {
				return FALSE;
			} else {
				stream_set_blocking($fp, TRUE);
				stream_set_timeout($fp, $timeout);
				@fwrite($fp, $out);
				$status = stream_get_meta_data($fp);
				if(!$status['timed_out']) {
					$starttime = time();
					while (!feof($fp)) {
						if(($header = @fgets($fp)) && ($header == "\r\n" ||  $header == "\n")) {
							break;
						} else {
							if(strtolower(substr($header, 0, 9)) == 'location:') {
								$location = trim(substr($header, 9));
								return self::fetch_url($location, $timeout, $post, $cookie, $deep + 1);
							}
						}
					}
		
					$stop = false;
					while(!feof($fp) && !$stop) {
						$data = fread($fp, ($limit == 0 || $limit > 8192 ? 8192 : $limit));
						$return .= $data;
						if($limit) {
							$limit -= strlen($data);
							$stop = $limit <= 0;
						}
						if(time() - $starttime > $timeout) break;
					}
				}
				@fclose($fp);
				return $return;
			}
		} elseif(function_exists('curl_init') && empty($cookie)) {
			$ch = curl_init();
			if(!empty($refer))curl_setopt ($ch, CURLOPT_REFERER, $refer);
			curl_setopt($ch, CURLOPT_URL, $url);
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
			curl_setopt($ch, CURLOPT_HEADER, 1);
			if($post) {
				curl_setopt($ch, CURLOPT_POST, 1);
				curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
			}
			if($sendcookie && !empty($cookiefile)) {
				curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiefile);
			}elseif(!empty($cookiefile)){
				curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiefile);
			}
			$data = curl_exec($ch);
			
			if(curl_errno($ch)) {
				throw new Exception('Errno'.curl_error($ch));//捕抓异常
			}
			if(!$data) {
				curl_close($ch);
				return '';
			}
			
			list($header, $data) = explode("\r\n\r\n", $data,2);
			/*$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
			if($http_code == 301 || $http_code == 302) {
				$matches = array();
				preg_match('/Location:(.*?)\n/', $header, $matches);
				$url = trim(array_pop($matches));
				curl_setopt($ch, CURLOPT_URL, $url);
				curl_setopt($ch, CURLOPT_HEADER, false);
				$data = curl_exec($ch);
			}*/
			curl_close($ch);
			return $data;  
		} elseif($allow_url_fopen && empty($post) && empty($cookie) && in_array('http', $w)) {
			// 尝试连接
			$opts = array ('http'=>array('method'=>'GET', 'timeout'=>$timeout)); 
			$context = stream_context_create($opts);  
			$html = file_get_contents($url, false, $context);  
			return $html;
		} else {
			new Log('fetch_url() failed: '.$url);
			return FALSE;
		}
	}
	
	
	/*
	多线程抓取数据，需要CURL支持
	*/
	public static function multi_fetch_url($urls) {
		if(!function_exists('curl_multi_init')) {
			$data = array();
			foreach($urls as $k=>$url) {
				$data[$k] = self::fetch_url($url);
			}
			return $data;
		}

		$multi_handle = curl_multi_init();
		foreach ($urls as $i => $url) {
			$conn[$i] = curl_init($url);
			curl_setopt($conn[$i], CURLOPT_RETURNTRANSFER, 1);
			$timeout = 3;
			curl_setopt($conn[$i], CURLOPT_CONNECTTIMEOUT, $timeout); // 超时 seconds
			curl_setopt($conn[$i], CURLOPT_FOLLOWLOCATION, 1);
			curl_multi_add_handle($multi_handle, $conn[$i]);
		}
		do {
			$mrc = curl_multi_exec($multi_handle, $active);
		} while ($mrc == CURLM_CALL_MULTI_PERFORM);
		while ($active and $mrc == CURLM_OK) {
			if (curl_multi_select($multi_handle) != - 1) {
				do {
					$mrc = curl_multi_exec($multi_handle, $active);
				} while ($mrc == CURLM_CALL_MULTI_PERFORM);
			}
		}
		foreach ($urls as $i => $url) {
			$data[$i] = curl_multi_getcontent($conn[$i]);
			curl_multi_remove_handle($multi_handle, $conn[$i]);
			curl_close($conn[$i]);
		}
		return $data;
	}
}

/*{TranslateTagEnd}*/

?>